"""
计算器智能体
处理数学计算和数据分析任务的智能体
"""

from typing import Dict, Any, List, Optional
import asyncio
import math
import statistics
import re
from decimal import Decimal, getcontext

from apps.agents.base_agent import BaseAgent, AgentType
from utils.logger import logger


class CalculatorAgent(BaseAgent):
    """计算器智能体"""
    
    def __init__(self, agent_id: str = "calculator_agent"):
        super().__init__(
            agent_id=agent_id,
            agent_type=AgentType.CALCULATOR,
            name="计算器智能体"
        )
        
        # 设置高精度计算
        getcontext().prec = 50
        
        # 支持的计算类型
        self.supported_operations = {
            "basic": self._basic_calculations,
            "scientific": self._scientific_calculations,
            "statistical": self._statistical_calculations,
            "financial": self._financial_calculations,
            "unit_conversion": self._unit_conversions,
            "expression": self._evaluate_expression
        }
        
        logger.info(f"计算器智能体初始化完成: {self.agent_id}")
    
    async def validate_input(self, input_data: Dict[str, Any]) -> bool:
        """验证输入数据"""
        
        # 检查计算类型
        calc_type = input_data.get("calculation_type", "expression")
        if calc_type not in self.supported_operations:
            logger.error(f"不支持的计算类型: {calc_type}")
            return False
        
        # 验证表达式计算
        if calc_type == "expression":
            expression = input_data.get("expression", "")
            if not expression or not isinstance(expression, str):
                logger.error("表达式无效")
                return False
            
            # 安全检查表达式
            if not self._is_safe_expression(expression):
                logger.error("表达式包含不安全内容")
                return False
        
        # 验证数值输入
        elif calc_type in ["basic", "statistical"]:
            numbers = input_data.get("numbers", [])
            if not isinstance(numbers, list) or len(numbers) == 0:
                logger.error("数值输入无效")
                return False
            
            for num in numbers:
                if not isinstance(num, (int, float)):
                    logger.error(f"无效的数值: {num}")
                    return False
        
        return True
    
    async def process_task(self, task_data: Dict[str, Any]) -> Dict[str, Any]:
        """处理计算任务"""
        
        calc_type = task_data.get("calculation_type", "expression")
        logger.info(f"开始处理计算任务: {calc_type}")
        
        try:
            # 获取对应的计算方法
            calculator = self.supported_operations.get(calc_type)
            if not calculator:
                raise ValueError(f"不支持的计算类型: {calc_type}")
            
            # 执行计算
            result = await calculator(task_data)
            
            # 添加元数据
            result.update({
                "calculation_type": calc_type,
                "timestamp": asyncio.get_event_loop().time(),
                "agent_id": self.agent_id
            })
            
            logger.info(f"计算任务完成: {calc_type}")
            return result
            
        except Exception as e:
            logger.error(f"计算任务失败: {str(e)}")
            raise
    
    async def _basic_calculations(self, task_data: Dict[str, Any]) -> Dict[str, Any]:
        """基础计算"""
        numbers = task_data.get("numbers", [])
        operation = task_data.get("operation", "sum")
        
        if not numbers:
            raise ValueError("缺少数值输入")
        
        results = {}
        
        # 求和
        if operation in ["sum", "all"]:
            results["sum"] = sum(numbers)
        
        # 平均值
        if operation in ["average", "mean", "all"]:
            results["average"] = statistics.mean(numbers)
        
        # 最大值
        if operation in ["max", "all"]:
            results["max"] = max(numbers)
        
        # 最小值
        if operation in ["min", "all"]:
            results["min"] = min(numbers)
        
        # 计数
        if operation in ["count", "all"]:
            results["count"] = len(numbers)
        
        # 乘积
        if operation in ["product", "all"]:
            product = 1
            for num in numbers:
                product *= num
            results["product"] = product
        
        return {
            "input_numbers": numbers,
            "operation": operation,
            "results": results if operation != "all" else results
        }
    
    async def _scientific_calculations(self, task_data: Dict[str, Any]) -> Dict[str, Any]:
        """科学计算"""
        operation = task_data.get("scientific_operation", "sqrt")
        value = task_data.get("value", 0)
        
        results = {}
        
        if operation == "sqrt":
            if value < 0:
                raise ValueError("负数不能开平方")
            results["result"] = math.sqrt(value)
            
        elif operation == "pow":
            exponent = task_data.get("exponent", 2)
            results["result"] = math.pow(value, exponent)
            results["exponent"] = exponent
            
        elif operation == "log":
            if value <= 0:
                raise ValueError("对数函数的参数必须为正数")
            base = task_data.get("base", 10)
            if base <= 0 or base == 1:
                raise ValueError("对数底数必须为正数且不等于1")
            results["result"] = math.log(value, base)
            results["base"] = base
            
        elif operation == "sin":
            results["result"] = math.sin(math.radians(value))
            
        elif operation == "cos":
            results["result"] = math.cos(math.radians(value))
            
        elif operation == "tan":
            results["result"] = math.tan(math.radians(value))
            
        elif operation == "factorial":
            if value < 0 or not isinstance(value, int):
                raise ValueError("阶乘的参数必须是非负整数")
            if value > 170:  # 避免数值过大
                raise ValueError("阶乘参数过大")
            results["result"] = math.factorial(int(value))
            
        else:
            raise ValueError(f"不支持的科学计算操作: {operation}")
        
        return {
            "operation": operation,
            "input_value": value,
            "results": results
        }
    
    async def _statistical_calculations(self, task_data: Dict[str, Any]) -> Dict[str, Any]:
        """统计计算"""
        data = task_data.get("data", [])
        
        if not data:
            raise ValueError("缺少数据输入")
        
        results = {}
        
        # 基础统计
        results["count"] = len(data)
        results["mean"] = statistics.mean(data)
        results["median"] = statistics.median(data)
        results["min"] = min(data)
        results["max"] = max(data)
        
        # 高级统计（如果数据量足够）
        if len(data) > 1:
            results["stdev"] = statistics.stdev(data)
            results["variance"] = statistics.variance(data)
            
            # 四分位数
            sorted_data = sorted(data)
            n = len(sorted_data)
            q1_index = n // 4
            q3_index = 3 * n // 4
            results["q1"] = sorted_data[q1_index]
            results["q3"] = sorted_data[q3_index]
            results["iqr"] = results["q3"] - results["q1"]
        
        return {
            "data": data,
            "statistical_results": results
        }
    
    async def _financial_calculations(self, task_data: Dict[str, Any]) -> Dict[str, Any]:
        """金融计算"""
        operation = task_data.get("financial_operation", "compound_interest")
        
        if operation == "compound_interest":
            principal = Decimal(str(task_data.get("principal", 0)))
            rate = Decimal(str(task_data.get("rate", 0))) / 100  # 转换为小数
            time = Decimal(str(task_data.get("time", 1)))
            n = Decimal(str(task_data.get("compounds_per_year", 1)))
            
            if principal <= 0 or rate < 0 or time <= 0 or n <= 0:
                raise ValueError("复利计算的参数必须为正数")
            
            # A = P(1 + r/n)^(nt)
            amount = principal * (1 + rate / n) ** (n * time)
            interest = amount - principal
            
            return {
                "operation": "compound_interest",
                "principal": float(principal),
                "rate": float(rate * 100),  # 转换回百分比
                "time": float(time),
                "compounds_per_year": int(n),
                "final_amount": float(amount),
                "total_interest": float(interest)
            }
        
        elif operation == "loan_payment":
            principal = Decimal(str(task_data.get("principal", 0)))
            annual_rate = Decimal(str(task_data.get("annual_rate", 0))) / 100
            years = Decimal(str(task_data.get("years", 1)))
            payments_per_year = Decimal(str(task_data.get("payments_per_year", 12)))
            
            if principal <= 0 or annual_rate < 0 or years <= 0 or payments_per_year <= 0:
                raise ValueError("贷款计算的参数必须为正数")
            
            if annual_rate == 0:
                payment = principal / (years * payments_per_year)
            else:
                periodic_rate = annual_rate / payments_per_year
                num_payments = years * payments_per_year
                
                # P = Pv * r / (1 - (1 + r)^-n)
                payment = principal * periodic_rate / (1 - (1 + periodic_rate) ** -num_payments)
            
            total_payment = payment * years * payments_per_year
            total_interest = total_payment - principal
            
            return {
                "operation": "loan_payment",
                "principal": float(principal),
                "annual_rate": float(annual_rate * 100),
                "years": float(years),
                "payments_per_year": int(payments_per_year),
                "monthly_payment": float(payment),
                "total_payment": float(total_payment),
                "total_interest": float(total_interest)
            }
        
        else:
            raise ValueError(f"不支持的金融计算操作: {operation}")
    
    async def _unit_conversions(self, task_data: Dict[str, Any]) -> Dict[str, Any]:
        """单位转换"""
        from_unit = task_data.get("from_unit", "")
        to_unit = task_data.get("to_unit", "")
        value = task_data.get("value", 0)
        
        # 定义转换因子
        conversions = {
            # 长度
            ("meter", "kilometer"): 0.001,
            ("kilometer", "meter"): 1000,
            ("meter", "centimeter"): 100,
            ("centimeter", "meter"): 0.01,
            ("mile", "kilometer"): 1.60934,
            ("kilometer", "mile"): 0.621371,
            
            # 重量
            ("kilogram", "gram"): 1000,
            ("gram", "kilogram"): 0.001,
            ("pound", "kilogram"): 0.453592,
            ("kilogram", "pound"): 2.20462,
            
            # 温度（需要特殊处理）
            ("celsius", "fahrenheit"): "special",
            ("fahrenheit", "celsius"): "special",
            
            # 时间
            ("second", "minute"): 1/60,
            ("minute", "second"): 60,
            ("minute", "hour"): 1/60,
            ("hour", "minute"): 60,
        }
        
        # 查找转换因子
        conversion_key = (from_unit.lower(), to_unit.lower())
        factor = conversions.get(conversion_key)
        
        if factor is None:
            raise ValueError(f"不支持的单位转换: {from_unit} -> {to_unit}")
        
        # 特殊处理温度转换
        if factor == "special":
            if conversion_key == ("celsius", "fahrenheit"):
                result = value * 9/5 + 32
            elif conversion_key == ("fahrenheit", "celsius"):
                result = (value - 32) * 5/9
            else:
                raise ValueError(f"不支持的温度转换")
        else:
            result = value * factor
        
        return {
            "from_unit": from_unit,
            "to_unit": to_unit,
            "input_value": value,
            "result": result,
            "conversion_factor": factor if factor != "special" else None
        }
    
    async def _evaluate_expression(self, task_data: Dict[str, Any]) -> Dict[str, Any]:
        """计算数学表达式"""
        expression = task_data.get("expression", "")
        
        if not expression:
            raise ValueError("缺少数学表达式")
        
        # 安全检查表达式
        if not self._is_safe_expression(expression):
            raise ValueError("表达式包含不安全内容")
        
        try:
            # 使用安全的表达式求值
            result = self._safe_eval(expression)
            
            return {
                "expression": expression,
                "result": result,
                "steps": self._show_calculation_steps(expression, result)
            }
            
        except Exception as e:
            raise ValueError(f"表达式计算失败: {str(e)}")
    
    def _is_safe_expression(self, expression: str) -> bool:
        """检查表达式是否安全"""
        # 只允许数学相关的字符
        allowed_pattern = r'^[0-9+\-*/().^\s]*$'
        if not re.match(allowed_pattern, expression):
            return False
        
        # 检查危险关键词
        dangerous_keywords = [
            'import', 'exec', 'eval', 'open', 'file', 'os', 'sys',
            '__', 'class', 'def', 'lambda', 'return', 'yield'
        ]
        
        expression_lower = expression.lower()
        for keyword in dangerous_keywords:
            if keyword in expression_lower:
                return False
        
        return True
    
    def _safe_eval(self, expression: str) -> float:
        """安全地计算数学表达式"""
        # 替换数学函数
        replacements = {
            'sin': 'math.sin',
            'cos': 'math.cos',
            'tan': 'math.tan',
            'sqrt': 'math.sqrt',
            'log': 'math.log',
            'exp': 'math.exp',
            'pi': 'math.pi',
            'e': 'math.e'
        }
        
        safe_expression = expression
        for old, new in replacements.items():
            safe_expression = safe_expression.replace(old, new)
        
        # 使用eval计算（在安全的环境中）
        allowed_names = {
            'math': math,
            'sin': math.sin,
            'cos': math.cos,
            'tan': math.tan,
            'sqrt': math.sqrt,
            'log': math.log,
            'exp': math.exp,
            'pi': math.pi,
            'e': math.e
        }
        
        return eval(safe_expression, {"__builtins__": {}}, allowed_names)
    
    def _show_calculation_steps(self, expression: str, result: float) -> List[str]:
        """显示计算步骤"""
        # 简单的步骤显示（可以根据需要扩展）
        steps = [
            f"输入表达式: {expression}",
            f"计算结果: {result}",
            f"结果类型: {'整数' if isinstance(result, int) else '小数'}",
            f"结果精度: {len(str(result).split('.')[-1]) if '.' in str(result) else 0} 位小数"
        ]
        
        return steps
    
    async def validate_calculation_result(self, result: Dict[str, Any]) -> bool:
        """验证计算结果的合理性"""
        
        # 检查数值范围
        if "result" in result:
            result_value = result["result"]
            if isinstance(result_value, (int, float)):
                # 检查结果是否在合理范围内
                if abs(result_value) > 1e15:
                    logger.warning(f"计算结果过大: {result_value}")
                    return False
                
                if abs(result_value) < 1e-15 and result_value != 0:
                    logger.warning(f"计算结果过小: {result_value}")
                    return False
        
        return True